#include "dma.h"

void myDMA_Init_M2M(uint32_t srcAddr, uint32_t destAddr, uint32_t dataLen)
{
    // RCC开启
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

    // 准备结构体初始化
    DMA_InitTypeDef DMA_initStruct = {0};
    // 外设的地址, 此处使用普通内存起始地址
    DMA_initStruct.DMA_PeripheralBaseAddr = srcAddr;
    // 存储器的地址, 对应内存中的某个地址, 此处使用普通内存的目标地址
    DMA_initStruct.DMA_MemoryBaseAddr = destAddr;
    // direction 表示方向
    DMA_initStruct.DMA_DIR = DMA_DIR_PeripheralSRC;
    // 要传输的数据个数
    DMA_initStruct.DMA_BufferSize = dataLen;
    // 是否使用地址递增, 使用的话, 源地址和目标地址每发送一个数据都递增
    DMA_initStruct.DMA_PeripheralInc = DMA_PeripheralInc_Enable;
    DMA_initStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
    // 存储器和外设对应的数据宽度
    DMA_initStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; // 源地址每次读取一个字节
    DMA_initStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;         // 发送端每次接收一个字节
    // 是否循环dma传输, 此处选否, 传完字节即停止
    DMA_initStruct.DMA_Mode = DMA_Mode_Normal;
    // 优先级, 总线资源不够时, 优先保证高优先级的通道运行
    // 四级: 低 中 高 非常高
    DMA_initStruct.DMA_Priority = DMA_Priority_Medium;
    // M2M模式, 如果两头都是存储器则设为Enable, 否则Disable
    DMA_initStruct.DMA_M2M = DMA_M2M_Enable;
    DMA_Init(DMA_CH_M2M, &DMA_initStruct);

    // 增加中断
    DMA_ITConfig(DMA_CH_M2M, DMA_IT_TC, ENABLE);
    NVIC_InitTypeDef NVIC_initStruct = {0};
    NVIC_initStruct.NVIC_IRQChannel = DMA1_Channel5_IRQn; // DMA1_Channel5_IRQHandler
    NVIC_initStruct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_initStruct.NVIC_IRQChannelPreemptionPriority = 2;
    NVIC_initStruct.NVIC_IRQChannelSubPriority = 2;
    NVIC_Init(&NVIC_initStruct);

    DMA_Cmd(DMA_CH_M2M, ENABLE);
}

void myDMA_Init_M2PCCOM(uint32_t srcAddr, uint32_t dataLen)
{
    // RCC开启
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

    // 准备结构体初始化
    DMA_InitTypeDef DMA_initStruct = {0};
    // 外设的地址, 此处对应USART1_TX对应的数据寄存器,即USART1->DR
    DMA_initStruct.DMA_PeripheralBaseAddr = (uint32_t)(&USART1->DR);
    // 存储器的地址, 对应内存中的某个地址, 此处使用普通内存的目标地址
    DMA_initStruct.DMA_MemoryBaseAddr = srcAddr;
    // direction 表示方向
    DMA_initStruct.DMA_DIR = DMA_DIR_PeripheralDST;
    // 要传输的数据个数
    DMA_initStruct.DMA_BufferSize = dataLen;
    // 是否使用地址递增, 使用的话, 源地址和目标地址每发送一个数据都递增
    DMA_initStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_initStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
    // 存储器和外设对应的数据宽度
    DMA_initStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; // 源地址每次读取一个字节
    DMA_initStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;         // 发送端每次接收一个字节
    // 是否循环dma传输, 此处选否, 传完字节即停止
    DMA_initStruct.DMA_Mode = DMA_Mode_Normal;
    // 优先级, 总线资源不够时, 优先保证高优先级的通道运行
    // 四级: 低 中 高 非常高
    DMA_initStruct.DMA_Priority = DMA_Priority_Medium;
    // M2M模式, 如果两头都是存储器则设为Enable, 否则Disable
    DMA_initStruct.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(DMA_CH_M2PCCOM, &DMA_initStruct);
}

void myDMA_Start_M2PCCOM(uint32_t dataLen)
{
    // 想要启动一次新的传输, 先停止, 再改待传输个数, 再启动
    DMA_Cmd(DMA_CH_M2PCCOM, DISABLE);
    DMA_SetCurrDataCounter(DMA_CH_M2PCCOM, dataLen);
    DMA_Cmd(DMA_CH_M2PCCOM, ENABLE);
}
